//
//  main.cpp
//  AdvPropTestsCpp
//
//  Created by Brian Bogard on 2/23/12.
//
//  --Revision History--
//  Harsh Vachhani on 03/04/12
//
//  Copyright 2012 ASU. All rights reserved.
//

#include <iostream>
#include <fstream>
#include <string>
#include <time.h>
#include "PropTesterConstants.h"
#include "PropTesterConfig.h"
#include "GraphData.pb.h"
#include "Graph.h"
#include "Node.h"
#include "GraphTester.h"
#include "ConfigConstants.h"

/* NOTE: When using this program, we're assuming all node numbers start are
 * 0 and are contiguous throughout.
 *
 */

using namespace std;

// HRV: Add -lrt to linker for timer
// Function to subtract two time-stamps
timespec diff(timespec start, timespec end)
{
	timespec temp;
	if ((end.tv_nsec-start.tv_nsec)<0) {
		temp.tv_sec = end.tv_sec-start.tv_sec-1;
		temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
	} else {
		temp.tv_sec = end.tv_sec-start.tv_sec;
		temp.tv_nsec = end.tv_nsec-start.tv_nsec;
	}
	return temp;
}

int main ( int argc, const char * argv[] )
{
	timespec tStart, tEnd;
	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tStart);
    if( argc <= PropTesterConstants::GRAPH_PROTO_BUF )
    {
        cerr << "Usage: AdvPropTester <config file> <graph proto buf>" << endl;
        exit( -1 );
    }
    
    // HRV: consts is coming hardcoded, can change later
    //string configFileName = argv[ PropTesterConstants::CONFIG_FILE ];
    //PropTesterConfig testerConfig( configFileName.c_str() );
    
    int numberOfGraphs =  ConfigConstants::DEFAULT_NUMBER_OF_GRAPHS;
    int initRedSelect = ConfigConstants::DEFAULT_INIT_RED_SELECT;
    float activeEdgeProb = ConfigConstants::DEFAULT_ACTIVE_EDGE_PROB;
    //Shahrzad
    int maxPropagationDist = ConfigConstants::DEFAULT_MAX_PROPAGATION_DIST;
    
    cout << "Settings:" << endl;
    cout << "Number of graphs: " << numberOfGraphs << endl;
    cout << "Initial red nodes: " << initRedSelect << endl;
    cout << "Active edge probability: " << activeEdgeProb << endl;
    cout << endl;
    
    cout << "Starting to load data..." << endl;
    GOOGLE_PROTOBUF_VERIFY_VERSION;
    
    graphData::Graph graphProtoBuf;
    

	// Read the existing address book.
	fstream input( argv[ PropTesterConstants::GRAPH_PROTO_BUF ], ios::in | ios::binary );
	if ( ! graphProtoBuf.ParseFromIstream( &input ) )
	{
		cerr << "Failed to parse address book." << endl;
		exit( -1 );
	}

    
    cout << "Finished loading graph data, now starting the graph" << endl;
    
    boost::shared_ptr< Graph > graphObj( new Graph() );
    
    for( int nodeIndex = 0; nodeIndex < graphProtoBuf.nodes_size(); ++nodeIndex )
    {
        const graphData::Node& node = graphProtoBuf.nodes( nodeIndex );
        graphObj->addNode( node.id(), Node( node.id() ) );
    }

    for( int edgeIndex = 0; edgeIndex < graphProtoBuf.edges_size(); ++edgeIndex )
    {
        const graphData::Edge& edge = graphProtoBuf.edges( edgeIndex );
        graphObj->addEdge( edge.source(), edge.target() );
    }

    google::protobuf::ShutdownProtobufLibrary();
    graphObj->showGraphInfo();

	GraphTester * gTester = new GraphTester( graphObj, activeEdgeProb, initRedSelect, GraphTester::DEGREE_CENTRALITY, numberOfGraphs, maxPropagationDist );

	cout << "Starting the tests" << endl;
	int blueNodesNeeded = gTester->runTests();
    
    cout <<  "Done" << endl;
    cout << "Blue Nodes needed: " << blueNodesNeeded << endl;

    cout << "Total time elasped: ";
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tEnd);
    cout<<diff(tStart,tEnd).tv_sec<<endl;
    return 0;
}

